package map
{
	import caves.*;
	import caves.points.*;
	import flash.display.BitmapData;
	import flash.geom.Point;
	import flash.utils.ByteArray;
	import utils.*;
	
	
	/**
	 * ...
	 * @author Jeroen Gildemacher
	 */
	public class MapSource
	{

		private var _cruisingHeight:int = 90;
		
		private var byteMap:BitmapData;
		
		private var _resourceColors:Vector.<uint> = new Vector.<uint>;
		private var _surfacePixels:Vector.<Point> = new Vector.<Point>;
		
		//vector of resourcepoints per resource type
		private var _resources:Vector.<Vector.<ResourcePoint>> = new Vector.<Vector.<ResourcePoint>>;
		//vector of putspaces per nr of spaces
		private var _putSpaces:Vector.<Vector.<SpacePoint>> = new Vector.<Vector.<SpacePoint>>;
		//private var _putSpaces:Vector.<SpacePoint>= new Vector.<SpacePoint>;
		private var _shafts:Vector.<ShaftSpace>= new Vector.<ShaftSpace>;
		private var _caves:Vector.<CaveSpace>= new Vector.<CaveSpace>;
		private var _tunnels:Vector.<TunnelSpace>= new Vector.<TunnelSpace>;
		
		private var _surfaceSpace:SurfaceSpace = new SurfaceSpace;
		
		private var _map:Vector.<Vector.<SpacePoint>>=new Vector.<Vector.<SpacePoint>>;
		
		
		public function MapSource()
		{
			byteMap = new BitmapData(1000, 600, true, 0xFF000000);
			setColors();
			fillByteMap();
		}
		
		public function getColors():Vector.<uint>
		{
			return _resourceColors;
		}
		
		private function setColors():void
		{
			var i:uint = 0
			var b1:uint;
			var b2:uint;
			var b3:uint;
			for (var c:int = 0; c < 8; c++)
			{
				b1 = (c & 1);
				b2 = (c & 2) / 2;
				b3 = (c & 4) / 4;
				i = 0;
				i += b1 * 128;
				i += b2 * 128 * 0x000100;
				i += b3 * 128 * 0x010000;
				i = i + 0xFF000000;
				_resourceColors.push(i);
				_resources.push(new Vector.<ResourcePoint>);
			}
		}
		
		private function fillByteMap():void
		{
			var c:uint;
			var vy:Vector.<SpacePoint>;
			_map = new Vector.<Vector.<SpacePoint>>;
			
			for (var x:int = 0; x < 1000; x++)
			{
				vy = new Vector.<SpacePoint>;
				for (var y:int = 0; y < 600; y++) {
					//above 100 is space
					if (y < 100) {
						byteMap.setPixel32(x, y, 0x00000000);
						vy.push(new SpacePoint(x,y, _surfaceSpace));
					}
					else {
						c = Math.floor(Math.random() * _resourceColors.length * (y / 600));
						if (c + 2 < _resourceColors.length)
						{
							c += 1;
						}
						byteMap.setPixel32(x, y, _resourceColors[c]);
						vy.push(new ResourcePoint(x,y,c,null));
					}
					
				}
				_map.push(vy);
			}
			
		}
		
		public function canMoveToPoint(p:Point):Boolean {
			if (p.x < 1 || p.y < 1 || p.x >= _map.length -1|| p.y >= _map[0].length-1) {
				return false;
			}
			if (_map[p.x][p.y] is ResourcePoint) {
				return false;
			}
			return true;
		}
		public function explorePoint(p:Point):void {
			var sa:SpacePoint = _map[above(p).x][above(p).y] ;
			var sb:SpacePoint = _map[below(p).x][below(p).y] ;
			var sr:SpacePoint = _map[toTheRight(p).x][toTheRight(p).y] ;
			var sl :SpacePoint = _map[toTheLeft(p).x][toTheLeft(p).y] ;
			
			if (sa is ResourcePoint) {
				updateResourceNr(ResourcePoint(sa));
			}
			if (sb is ResourcePoint) {
				updateResourceNr(ResourcePoint(sb));
				if (!(p is TunnelPoint) &&
					!(p is ShaftPoint)) {
				updatePutSpaces(_map[p.x][p.y]);
				}
			}
			if (sr is ResourcePoint) {
				updateResourceNr(ResourcePoint(sr));
			}
			if (sl is ResourcePoint) {
				updateResourceNr(ResourcePoint(sl));
			}
		}
		public function getNrResource(resourceType:int):int {
			return _resources[resourceType].length;
		}
		private function updateResourceNr(p:ResourcePoint):void {
			_resources[p.resource].push(p);
		}
		private function updatePutSpaces(discoveredPoint:SpacePoint):void {
			var firstVector:Vector.<SpacePoint> = null;
			var i:int;
			for each (var v:Vector.<SpacePoint> in _putSpaces) {
				//if point is not already in collection and next to a point in collection
				//add point to collection
				i = v.indexOf(discoveredPoint);
				if (i<0 && v.length<10){
					for each (var s:SpacePoint in v) {
						if ( isToTheLeftOf(discoveredPoint,s) || isToTheRightOf(discoveredPoint,s)) {
							if (firstVector==null){
								firstVector = v;
								v.push(discoveredPoint);
							} else {
								v.concat(firstVector);
								return;
							}
						}
					}
				}
			}
			//if no other adjacent vectors found create new one
			if (firstVector == null) {
				firstVector = new Vector.<SpacePoint>;
				firstVector.push(discoveredPoint);
				_putSpaces.push(firstVector);
			}
		}

		private function updatePutSpacesAfterRemove(removedPoint:SpacePoint):void {
			for each(var v:Vector.<SpacePoint> in _putSpaces) {
				for each (var sp:SpacePoint in v){
					if (removedPoint == sp) {
						var x:int = removedPoint.x;
						var leftVector:Vector.<SpacePoint> = new Vector.<SpacePoint>;
						var rightVector:Vector.<SpacePoint> = new Vector.<SpacePoint>;
						for each (var spp:SpacePoint in v) {
							if (spp.x < removedPoint.x) {
								leftVector.push(spp);
							}
							if (spp.x > removedPoint.x) {
								rightVector.push(spp);
							}
						}
						if (leftVector.length > 0)_putSpaces.push(leftVector);
						if (rightVector.length > 0)_putSpaces.push(rightVector);
						_putSpaces.splice(_putSpaces.indexOf(v), 1);
						return;
					}
				}
			}
		}
		
		
		public function getAllSpaces():Vector.<AbstractSpace> {
			var allSpaces:Vector.<AbstractSpace> = new Vector.<AbstractSpace>;
			allSpaces.concat(_caves);
			allSpaces.concat(_shafts);
			allSpaces.concat(_surfaceSpace);
			allSpaces.concat(_tunnels);
			return allSpaces;
		}
		
		public function inTunnel(p:Point):Boolean {
			if (_map[p.x][p.y] is TunnelPoint) return true;
			return false;
		}
		public function inCave(p:Point):Boolean {
			if (_map[p.x][p.y] is CavePoint) return true;
			return false;
		}
		public function inShaft(p:Point):Boolean {
			if (_map[p.x][p.y] is ShaftPoint) return true;
			return false;
		}
		public function onSurface(p:Point):Boolean {
			if (!(_map[p.x][p.y] is ShaftPoint)
				&& !(_map[p.x][p.y] is CavePoint)
				&& !(_map[p.x][p.y] is TunnelPoint)) {
					return true;	
			}
			return false;
		}
		
		
		public function getResourceCombo(rc:Vector.<int>):Point {
			for each (var v:Vector.<ResourcePoint> in _resources) {
				for each (var s:ResourcePoint in v) {
					for (var i:int= 0; i < rc.length; i++) {
						if (!(_map[s.x + i][s.y] is ResourcePoint)||  
							!(ResourcePoint(_map[s.x + i][s.y]).resource == rc[i]) ||
							_map[s.x + i][s.y-1] is ResourcePoint) {
							break;
						}
					}
					return s;
				}
			}
			return null;
		}
		
		//    GETTERS AND SETTERS  
		public function getByteMap():BitmapData
		{
			return byteMap;
		}
		
		
		public function get cruisingHeight():int 
		{
			return _cruisingHeight;
		}
		
		
		
	}

}